﻿using Nop.Core.Data;
using Nop.Core.Domain.Catalog;
using Nop.Plugin.Misc.Reservations.Models;
using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;

namespace Nop.Plugin.Misc.Reservations.Services
{
    public class ReservationBusiness : IReservationBusiness
    {
        private readonly IRepository<Reservation> _reservationRepository;

        private IQueryable<Reservation> ReservationTable
        {
            get
            {
                return _reservationRepository.Table;
            }
        }

        public ReservationBusiness(IRepository<Reservation> reservationRepository, 
            IRepository<Product> productRepository)
        {
            _reservationRepository = reservationRepository;
        }

        public Reservation ReservationById(int reservationID)
        {
            if (reservationID == 0)
            {
                return null;
            }
            return _reservationRepository.GetById(reservationID);
        }

        public Reservation CurrentReservation(int customerId, DateTime selectedDate, int tableIndex)
        {
            return BookedReservationsByDate(selectedDate)
                .Where(r => r.CustomerID == customerId 
                    && r.ReserveDate == selectedDate
                    && r.TableIndex == tableIndex)
                .FirstOrDefault();
        }

        public Reservation CheckReservationConflict(DateTime selectedDate, int tableIndex)
        {
            return BookedReservationsByDate(selectedDate)
                .Where(r => r.ReserveDate == selectedDate
                    && r.TableIndex == tableIndex
                    && !r.Deleted)
                .FirstOrDefault();
        }

        public IList<Reservation> ReservationsByDate(DateTime startDate, DateTime endDate)
        {
            IList<Reservation> reservations = ReservationTable
                .Where(r => EntityFunctions.TruncateTime(r.ReserveDate) >= startDate.Date
                    && EntityFunctions.TruncateTime(r.ReserveDate) <= endDate.Date)
                .ToList();

            return reservations;
        }

        public IList<Reservation> ReservationsByCustomer(int customerID)
        {
            IList<Reservation> reservations = ReservationTable
                .Where(r => r.CustomerID == customerID)
                .ToList();

            return reservations;
        }

        public IList<Reservation> ReservationsByProductID(int productID, DateTime startDate, DateTime endDate)
        {
            IList<Reservation> reservations = ReservationTable
                .Where(r => r.ProductID == productID
                    && r.ReserveDate >= startDate
                    && r.ReserveDate <= endDate)
                .ToList();

            return reservations;
        }

        public IList<Reservation> ReservationsByOrderGuid(Guid orderGuid)
        {
            if (orderGuid == null)
            {
                return new List<Reservation>();
            }
            IList<Reservation> reservations = ReservationTable
                .Where(r => r.OrderGuid == orderGuid)
                .ToList();

            return reservations;
        }

        public IList<Reservation> BookedReservationsByDate(DateTime selectedDate)
        {
            return ReservationsByDate(selectedDate, selectedDate)
                .Where(r => !r.Deleted)
                .ToList();
        }

        public IList<Reservation> CurrentReservationsByCustomerId(int customerId)
        {
            return ReservationsByCustomer(customerId)
                .Where(r => r.Status == (int)ReservationStatusType.OnHold
                    && !r.Deleted)
                .ToList();
        }

        public void Insert(Reservation reservation)
        {
            if (reservation == null)
            {
                throw new ArgumentNullException("reservation");
            }
            _reservationRepository.Insert(reservation);
        }

        public void Update(Reservation reservation)
        {
            if (reservation == null)
            {
                throw new ArgumentNullException("reservation");
            }
            _reservationRepository.Update(reservation);
        }

        public void Remove(Reservation reservation)
        {
            if (reservation == null)
            {
                throw new ArgumentNullException("reservation");
            }
            reservation.Deleted = true;
            Update(reservation);
        }
    }
}
